package com.mo.lib.view.progressview

import android.animation.Animator
import android.animation.ValueAnimator
import android.content.Context
import android.graphics.*
import android.text.TextPaint
import android.text.TextUtils
import android.util.AttributeSet
import android.util.DisplayMetrics
import android.util.TypedValue
import com.mo.lib.R
import com.mo.lib.view.BaseView

/**
 * @ author：mo
 * @ data：:
 * @ 功能：
 */
class CircleProgressView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) :
    BaseView(context, attrs, defStyleAttr) {

    /**笔画描边的宽度 */
    private var mStrokeWidth = 0f

    /**开始角度(默认从12点钟方向开始) */
    var startAngle = 270
        private set

    /**扫描角度(一个圆) */
    var sweepAngle = 360
        private set

    /**圆心坐标x */
    var circleCenterX = 0f
        private set

    /**圆心坐标y */
    var circleCenterY = 0f
        private set

    /** 圆正常颜色*/
    private var mNormalColor = -0x373738

    /** 进度颜色*/
    private var mProgressColor = -0xb01554

    /**是否使用着色器 */
    private var isShader = true

    /** 着色器*/
    private var mShader: Shader? = null

    /** 着色器颜色*/
    private var mShaderColors = intArrayOf(-0xb01554, -0x5722af, -0x172cf1, -0x5722af, -0xb01554)

    /**半径 */
    var radius = 0f
        private set

    /** 内圆与外圆的间距*/
    private var mCirclePadding = 0f

    /**刻度间隔的角度大小 */
    private var mTickSplitAngle = 5

    /** 刻度的角度大小*/
    private var mBlockAngle = 1

    /** 刻度偏移的角度大小*/
    private var mTickOffsetAngle = 0f

    /** 总刻度数*/
    private var mTotalTickCount = 0

    /**最大进度 */
    private var mMax = 100

    /**当前进度 */
    private var mProgress = 0

    /** 动画持续的时间*/
    private var mDuration = 500

    /** 标签内容*/
    private var mLabelText: String? = null

    /** 字体大小*/
    private var mLabelTextSize = 0f

    /** 字体颜色*/
    private var mLabelTextColor = -0xcccccd

    /** 标签内容距圆形内间距*/
    private var mLabelPaddingLeft = 0f
    private var mLabelPaddingTop = 0f
    private var mLabelPaddingRight = 0f
    private var mLabelPaddingBottom = 0f
    /**进度百分比 */
    var progressPercent = 0
        private set

    /** 是否显示标签文字*/
    private var isShowLabel = true

    /**是否默认显示百分比为标签文字*/
    private var isShowPercentText = true

    /** 是否显示外边框刻度*/
    private var isShowTick = true

    /** 是否旋转*/
    private var isTurn = false

    /** 是否是圆形线冒（圆角弧度）*/
    private var isCapRound = true
    private var isMeasureCircle = false
    private var mOnChangeListener: OnChangeListener? = null

    init {
        val a = context.obtainStyledAttributes(attrs, R.styleable.KCircleProgressView)
        val displayMetrics = displayMetrics
        mStrokeWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 12f, displayMetrics)
        mLabelTextSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 30f, displayMetrics)
        mCirclePadding = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10f, displayMetrics)
        val size = a.indexCount
        for (i in 0 until size) {
            val attr = a.getIndex(i)
            if (attr == R.styleable.KCircleProgressView_cpvStrokeWidth) {
                mStrokeWidth = a.getDimension(attr, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 12f, displayMetrics))
            } else if (attr == R.styleable.KCircleProgressView_cpvNormalColor) {
                mNormalColor = a.getColor(attr, -0x373738)
            } else if (attr == R.styleable.KCircleProgressView_cpvProgressColor) {
                mProgressColor = a.getColor(attr, -0xb01554)
                isShader = false
            } else if (attr == R.styleable.KCircleProgressView_cpvStartAngle) {
                startAngle = a.getInt(attr, 270)
            } else if (attr == R.styleable.KCircleProgressView_cpvSweepAngle) {
                sweepAngle = a.getInt(attr, 360)
            } else if (attr == R.styleable.KCircleProgressView_cpvMax) {
                mMax = a.getInt(attr, 100)
            } else if (attr == R.styleable.KCircleProgressView_cpvProgress) {
                mProgress = a.getInt(attr, 0)
            } else if (attr == R.styleable.KCircleProgressView_cpvDuration) {
                mDuration = a.getInt(attr, 500)
            } else if (attr == R.styleable.KCircleProgressView_cpvLabelText) {
                mLabelText = a.getString(attr)
            } else if (attr == R.styleable.KCircleProgressView_cpvLabelTextSize) {
                mLabelTextSize = a.getDimension(attr, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 30f, displayMetrics))
            } else if (attr == R.styleable.KCircleProgressView_cpvLabelTextColor) {
                mLabelTextColor = a.getColor(attr, -0xcccccd)
            } else if (attr == R.styleable.KCircleProgressView_cpvShowLabel) {
                isShowLabel = a.getBoolean(attr, isShowLabel)
            } else if (attr == R.styleable.KCircleProgressView_cpvShowTick) {
                isShowTick = a.getBoolean(attr, isShowTick)
            } else if (attr == R.styleable.KCircleProgressView_cpvCirclePadding) {
                mCirclePadding = a.getDimension(attr, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10f, displayMetrics))
            } else if (attr == R.styleable.KCircleProgressView_cpvTickSplitAngle) {
                mTickSplitAngle = a.getInt(attr, mTickSplitAngle)
            } else if (attr == R.styleable.KCircleProgressView_cpvBlockAngle) {
                mBlockAngle = a.getInt(attr, mBlockAngle)
            } else if (attr == R.styleable.KCircleProgressView_cpvTickOffsetAngle) {
                mTickOffsetAngle = a.getInt(attr, 0).toFloat()
            } else if (attr == R.styleable.KCircleProgressView_cpvTurn) {
                isTurn = a.getBoolean(attr, isTurn)
            } else if (attr == R.styleable.KCircleProgressView_cpvCapRound) {
                isCapRound = a.getBoolean(attr, isCapRound)
            } else if (attr == R.styleable.KCircleProgressView_cpvLabelPaddingLeft) {
                mLabelPaddingLeft = a.getDimension(attr, 0f)
            } else if (attr == R.styleable.KCircleProgressView_cpvLabelPaddingTop) {
                mLabelPaddingTop = a.getDimension(attr, 0f)
            } else if (attr == R.styleable.KCircleProgressView_cpvLabelPaddingRight) {
                mLabelPaddingRight = a.getDimension(attr, 0f)
            } else if (attr == R.styleable.KCircleProgressView_cpvLabelPaddingBottom) {
                mLabelPaddingBottom = a.getDimension(attr, 0f)
            }
        }
        isShowPercentText = TextUtils.isEmpty(mLabelText)
        a.recycle()
        progressPercent = (mProgress * 100.0f / mMax).toInt()
        mTextPaint = TextPaint()
        mTotalTickCount = (1.0f * sweepAngle / (mTickSplitAngle + mBlockAngle)).toInt()
    }

    private val displayMetrics: DisplayMetrics
        private get() = resources.displayMetrics

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        val defaultValue = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 200f, displayMetrics).toInt()
        val width = measureHandler(widthMeasureSpec, defaultValue)
        val height = measureHandler(heightMeasureSpec, defaultValue)

        //圆心坐标
        circleCenterX = (width + paddingLeft - paddingRight) / 2.0f
        circleCenterY = (height + paddingTop - paddingBottom) / 2.0f //计算间距
        val padding = Math.max(paddingLeft + paddingRight, paddingTop + paddingBottom) //半径=视图宽度-横向或纵向内间距值 - 画笔宽度
        radius = (width - padding - mStrokeWidth) / 2.0f - mCirclePadding

        //默认着色器
        mShader = SweepGradient(circleCenterX, circleCenterX, mShaderColors, null)
        isMeasureCircle = true
        setMeasuredDimension(width, height)
    }

    /**
     * 测量
     * @param measureSpec
     * @param defaultSize
     * @return
     */
    private fun measureHandler(measureSpec: Int, defaultSize: Int): Int {
        var result = defaultSize
        val measureMode = MeasureSpec.getMode(measureSpec)
        val measureSize = MeasureSpec.getSize(measureSpec)
        if (measureMode == MeasureSpec.EXACTLY) {
            result = measureSize
        } else if (measureMode == MeasureSpec.AT_MOST) {
            result = Math.min(defaultSize, measureSize)
        }
        return result
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        drawArc(canvas)
        drawText(canvas)
    }

    /**
     * 绘制弧形(默认为一个圆)
     * @param canvas
     */
    private fun drawArc(canvas: Canvas) {
        mPaint!!.reset()
        mPaint!!.isAntiAlias = true
        mPaint!!.style = Paint.Style.STROKE
        mPaint!!.strokeWidth = mStrokeWidth
        if (isShowTick) { //是否显示外边框刻度
            val tickDiameter = radius * 2
            val tickStartX = circleCenterX - radius
            val tickStartY = circleCenterY - radius
            val rectF = RectF(tickStartX, tickStartY, tickStartX + tickDiameter, tickStartY + tickDiameter)
            val currentBlockIndex = (progressPercent / 100f * mTotalTickCount).toInt()
            if (isTurn) {
                for (i in 0 until mTotalTickCount) { //底层未选中刻度
                    mPaint!!.shader = null
                    mPaint!!.color = mNormalColor //绘制外边框刻度
                    canvas.drawArc(rectF, i * (mBlockAngle + mTickSplitAngle) + startAngle + mTickOffsetAngle, mBlockAngle.toFloat(), false, mPaint!!)
                }
                for (i in currentBlockIndex until currentBlockIndex + currentBlockIndex) { //已选中的刻度
                    if (isShader && mShader != null) {
                        mPaint!!.shader = mShader
                    } else {
                        mPaint!!.color = mProgressColor
                    } //绘制外边框刻度
                    canvas.drawArc(rectF, i * (mBlockAngle + mTickSplitAngle) + startAngle + mTickOffsetAngle, mBlockAngle.toFloat(), false, mPaint!!)
                }
            } else {
                for (i in 0 until mTotalTickCount) {
                    if (i < currentBlockIndex) { //已选中的刻度
                        if (isShader && mShader != null) {
                            mPaint!!.shader = mShader
                        } else {
                            mPaint!!.color = mProgressColor
                        } //绘制外边框刻度
                        canvas.drawArc(rectF, i * (mBlockAngle + mTickSplitAngle) + startAngle + mTickOffsetAngle, mBlockAngle.toFloat(), false, mPaint!!)
                    } else if (mNormalColor != 0) { //未选中的刻度
                        mPaint!!.shader = null
                        mPaint!!.color = mNormalColor //绘制外边框刻度
                        canvas.drawArc(rectF, i * (mBlockAngle + mTickSplitAngle) + startAngle + mTickOffsetAngle, mBlockAngle.toFloat(), false, mPaint!!)
                    }
                }
            }
        }
        mPaint!!.shader = null
        if (isCapRound) {
            mPaint!!.strokeCap = Paint.Cap.ROUND
        }

        //进度圆半径
        val circleRadius = if (isShowTick) radius - mCirclePadding - mStrokeWidth else radius
        val diameter = circleRadius * 2
        val startX = circleCenterX - circleRadius
        val startY = circleCenterY - circleRadius
        val rectF1 = RectF(startX, startY, startX + diameter, startY + diameter)
        if (mNormalColor != 0) {
            mPaint!!.color = mNormalColor //绘制底层弧形
            canvas.drawArc(rectF1, startAngle.toFloat(), sweepAngle.toFloat(), false, mPaint!!)
        }

        //着色器不为空则设置着色器，反之用纯色
        if (isShader && mShader != null) {
            mPaint!!.shader = mShader
        } else {
            mPaint!!.color = mProgressColor
        }
        if (isTurn) { //绘制当前进度弧形
            canvas.drawArc(rectF1, startAngle + sweepAngle * ratio, sweepAngle * ratio, false, mPaint!!)
        } else { //绘制当前进度弧形
            canvas.drawArc(rectF1, startAngle.toFloat(), sweepAngle * ratio, false, mPaint!!)
        }
    }

    /**
     * 绘制中间的文本
     * @param canvas
     */
    private fun drawText(canvas: Canvas) {
        if (!isShowLabel) {
            return
        }
        mTextPaint!!.reset()
        mTextPaint!!.isAntiAlias = true
        mTextPaint!!.style = Paint.Style.FILL_AND_STROKE
        mTextPaint!!.textSize = mLabelTextSize
        mTextPaint!!.color = mLabelTextColor
        mTextPaint!!.textAlign = Paint.Align.CENTER
        val fontMetrics = mTextPaint!!.fontMetrics // 计算文字高度
        val fontHeight = fontMetrics.bottom - fontMetrics.top // 计算文字baseline
        val textBaseX = width / 2 + mLabelPaddingLeft - mLabelPaddingRight
        val textBaseY = height - (height - fontHeight) / 2 - fontMetrics.bottom + mLabelPaddingTop - mLabelPaddingBottom
        if (isShowPercentText) { //是否显示百分比
            canvas.drawText("$progressPercent%", textBaseX, textBaseY, mTextPaint!!)
        } else if (!TextUtils.isEmpty(mLabelText)) { //显示自定义文本
            canvas.drawText(mLabelText!!, textBaseX, textBaseY, mTextPaint!!)
        }
    }

    /**
     * 显示进度动画效果（根据当前已有进度开始）
     * @param progress
     */
    fun showAppendAnimation(progress: Int) {
        showAnimation(mProgress, progress, mDuration)
    }
    /**
     * 显示进度动画效果
     * @param progress
     * @param duration 动画时长
     */
    /**
     * 显示进度动画效果
     * @param progress
     */
    @JvmOverloads
    fun showAnimation(progress: Int, duration: Int = mDuration) {
        showAnimation(0, progress, duration)
    }
    /**
     * 显示进度动画效果，从from到to变化
     * @param from
     * @param to
     * @param duration 动画时长
     * @param listener
     */
    /**
     * 显示进度动画效果，从from到to变化
     * @param from
     * @param to
     * @param duration 动画时长
     */
    @JvmOverloads
    fun showAnimation(from: Int, to: Int, duration: Int, listener: Animator.AnimatorListener? = null) {
        mDuration = duration
        mProgress = from
        val valueAnimator = ValueAnimator.ofInt(from, to)
        valueAnimator.duration = duration.toLong()
        valueAnimator.addUpdateListener { animation -> progress = animation.animatedValue as Int }
        if (listener != null) {
            valueAnimator.removeAllUpdateListeners()
            valueAnimator.addListener(listener)
        }
        valueAnimator.start()
    }

    /**
     * 进度比例
     * @return
     */
    private val ratio: Float
        private get() = mProgress * 1.0f / mMax

    /**
     * 设置正常颜色
     * @param color
     */
    fun setNormalColor(color: Int) {
        mNormalColor = color
        invalidate()
    }

    /**
     * 设置着色器
     * @param shader
     */
    fun setShader(shader: Shader?) {
        isShader = true
        mShader = shader
        invalidate()
    }

    /**
     * 设置进度颜色（通过着色器实现渐变色）
     * @param colors
     */
    fun setProgressColors( colors: IntArray) {
        if (isMeasureCircle) {
            val shader: Shader = SweepGradient(circleCenterX, circleCenterX, colors, null)
            setShader(shader)
        } else {
            mShaderColors = colors
            isShader = true
        }
    }

    /**
     * 设置进度颜色（纯色）
     * @param color
     */
    fun setProgressColor(color: Int) {
        isShader = false
        mProgressColor = color
        invalidate()
    }

    /**
     * 设置进度颜色
     * @param resId
     */
    fun setProgressColorResource(resId: Int) {
        val color = resources.getColor(resId)
        setProgressColor(color)
    }

    /**
     * 设置是否显示外环刻度
     * @param isShowTick
     */
    fun setShowTick(isShowTick: Boolean) {
        this.isShowTick = isShowTick
        invalidate()
    }

    /**
     * 设置是否旋转
     * @param isTurn
     */
    fun setTurn(isTurn: Boolean) {
        this.isTurn = isTurn
        invalidate()
    }

    /**
     * 是否是圆形线冒（圆角弧度）
     * @param capRound
     */
    fun setCapRound(capRound: Boolean) {
        isCapRound = capRound
        invalidate()
    }

    /**
     * 设置最大进度
     * @param max
     */
    var max: Int
        get() = mMax
        set(max) {
            mMax = max
            invalidate()
        }

    /**
     * 设置当前进度
     * @param progress
     */
    var progress: Int
        get() = mProgress
        set(progress) {
            mProgress = progress
            progressPercent = (mProgress * 100.0f / mMax).toInt()
            invalidate()
            if (mOnChangeListener != null) {
                mOnChangeListener!!.onProgressChanged(mProgress.toFloat(), mMax.toFloat())
            }
        }

    /**
     * 设置标签文本
     * @param labelText
     */
    var labelText: String?
        get() = mLabelText
        set(labelText) {
            mLabelText = labelText
            isShowPercentText = TextUtils.isEmpty(labelText)
            invalidate()
        }

    fun isShowLabel(): Boolean {
        return isShowLabel
    }

    fun isShowPercentText(): Boolean {
        return isShowPercentText
    }

    fun isShowTick(): Boolean {
        return isShowTick
    }

//    fun isTurn(): Boolean {
//        return isTurn
//    }

    fun isCapRound(): Boolean {
        return isCapRound
    }

    fun setShowLabel(showLabel: Boolean) {
        isShowLabel = showLabel
        invalidate()
    }

    fun setShowPercentText(showPercentText: Boolean) {
        isShowPercentText = showPercentText
        invalidate()
    }

    fun setLabelPaddingLeft(labelPaddingLeft: Float) {
        mLabelPaddingLeft = labelPaddingLeft
        invalidate()
    }

    fun setLabelPaddingTop(labelPaddingTop: Float) {
        mLabelPaddingTop = labelPaddingTop
        invalidate()
    }

    fun setLabelPaddingRight(labelPaddingRight: Float) {
        mLabelPaddingRight = labelPaddingRight
        invalidate()
    }

    fun setLabelPaddingBottom(labelPaddingBottom: Float) {
        mLabelPaddingBottom = labelPaddingBottom
        invalidate()
    }

    /**
     * 如果自定义设置过[.setLabelText] 或通过xml设置过`app:labelText`则
     * 返回[.mLabelText]，反之默认返回百分比[.mProgressPercent]
     * @return
     */
    val text: String?
        get() = if (isShowPercentText) {
            "$progressPercent%"
        } else mLabelText
    var labelTextColor: Int
        get() = mLabelTextColor
        set(color) {
            mLabelTextColor = color
            invalidate()
        }

    fun setLabelTextColorResource(resId: Int) {
        val color = resources.getColor(resId)
        labelTextColor = color
    }

    fun setLabelTextSize(textSize: Float) {
        setLabelTextSize(TypedValue.COMPLEX_UNIT_SP, textSize)
    }

    fun setLabelTextSize(unit: Int, textSize: Float) {
        val size = TypedValue.applyDimension(unit, textSize, displayMetrics)
        if (mLabelTextSize != size) {
            mLabelTextSize = size
            invalidate()
        }
    }

    /**
     * 设置进度改变监听
     * @param onChangeListener
     */
    fun setOnChangeListener(onChangeListener: OnChangeListener?) {
        mOnChangeListener = onChangeListener
    }


    interface OnChangeListener {
        fun onProgressChanged(progress: Float, max: Float)
    }

}